package pl.edu.pw.elka.tinyrepo.dataserver.server;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.rmi.RemoteException;

import pl.edu.pw.elka.tinyrepo.common.HTTPHeaderType;
import pl.edu.pw.elka.tinyrepo.common.Request;
import pl.edu.pw.elka.tinyrepo.common.Response;
import pl.edu.pw.elka.tinyrepo.common.Request;
import pl.edu.pw.elka.tinyrepo.common.RequestHandler;
import pl.edu.pw.elka.tinyrepo.common.StatusCode;
import pl.edu.pw.elka.tinyrepo.gate.server.GateFacade;

/**
 * Request handler dla metody GET. Serwer danych
 * sprawdza czy plik do ktorego odwoluje sie request
 * istnieje rzeczwiscie na dysku i wysyla odpowiednio Response OK + dane
 * lub NOT_FOUND.
 * TODO ew. uzupelnic obsluge o wiecej kodow statusu. 
 * 
 * @author Piotr Jarosik
 */
class GETRequestHandler extends DataServerRequestHandler {
   /** Rozmiar bufora przy odczytywaniu danych. */
   static final int BUFFER_SIZE = 256;
   /** Plik do ktorego odwoluje sie klient. */
   private File requestedFile = null;
   
   /**
    * @param dataCatalog - root katalog dla serwera.
    */
   public GETRequestHandler(File dataCatalog, GateFacade gate) {
      this.dataCatalog = dataCatalog;
      this.gate = gate;
   }
   
   @Override
   public void run() {
      FileInputStream in = null;
      OutputStream out = null;
      try {
         if(incomming == null || request == null || dataCatalog == null)
            throw new RuntimeException("DATA SRV: impl problem"); // FIXME wyslac jeszcze ew. odpowiedz bledna
         
         // poki co, wystarczy request line, wiecej info nie potrzebujemy
         // przygotowanie response i wyslanie danych
         out = incomming.getOutputStream(); // strumien do klienta
         in = loadFile(request.getPath()); // strumien pliku z ktorego bedziemy czytac
         Response r = new Response(StatusCode.OK); // bedzie probowac wyslac
         r.addHeader(HTTPHeaderType.CONTENT_LENGTH, (new Integer(in.available())).toString()); // TODO potencjalne bledy z available
         r.write(out); // wysylamy Response ze OK
         System.out.println("Sent response: "+r);
         // udalo sie wyslac response, teraz przepompowujemy plik z danymi
         DataServerRequestHandler.writeBytes(out, in, BUFFER_SIZE);
         // i koniec
      } 
      catch (FileNotFoundException e) { // pliku najprawdopodobniej nie ma
        e.printStackTrace();
        Response r = new Response(StatusCode.NOT_FOUND);
        //TODO mozliwe, ze cos jeszcze do Response
        r.write(out);
        // poinformuj jeszcze brame o tym przypadku - niech odnotuje to ew. w swoim deskryptorze
        try {
         gate.dropFile(request.getPath()); // sprobuj usunac dany plik
        } 
        catch (RemoteException e1) {
           e1.printStackTrace();
        }
      } 
      catch (IOException e) { // cos nie wyszlo przy czytaniu z pliku lub wysylaniu danych - przerwij wysylanie danych do klienta i wyswietl komunikat o bledzie w serwerze
         e.printStackTrace(); // wypisywac bardziej elegancki komunikat
      } 
      catch (Exception e) {
         e.printStackTrace();
      }  
      finally {
         try {
            in.close(); // zamykamy plik
            // socket jest zamykany w klasach DAVServer.java
         } catch (IOException e) {
            e.printStackTrace();
         }
      }
   }

   @Override
   public RequestHandler copy() {
      return new GETRequestHandler(dataCatalog, gate);
   }

   /**
    * Zwraca strumien pliku
    * 
    * @param path
    * @return
    * @throws FileNotFoundException
    */
   private FileInputStream loadFile(String path) throws FileNotFoundException {
      if(path == null || path.length() == 0) // czy sciezka pusta?
         throw new FileNotFoundException();
      requestedFile = new File(dataCatalog, path);
      if(!requestedFile.canRead() || requestedFile.isDirectory())
         throw new FileNotFoundException(); // FIXME data server szuka tylko plikow, jezeli natrafi na katalog to file not found. Czy nie lepiej inny response?
      FileInputStream in = new FileInputStream(requestedFile);
      return in;
   }
}
